AuthService   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 91
dl 0
loc 117
ccs 27
cts 27
cp 1
rs 10
c 0
b 0
f 0
wmc 10

7 Functions

Rating   Name   Duplication   Size   Complexity  
A getGithubUser 0 11 1
A createToken 0 9 1
A findOrCreateUser 0 19 2
A getGithubToken 0 16 1
A validateUserById 0 10 2
A exchangeGithubCode 0 24 2
A getStatus 0 10 1
1 9
import { Injectable, ForbiddenException } from '@nestjs/common';
2 9
import { JwtService } from '@nestjs/jwt';
3 9
import { HttpService } from '@nestjs/axios';
4 9
import { InjectRepository } from '@nestjs/typeorm';
5 9
import { Repository } from 'typeorm';
6 9
import { firstValueFrom } from 'rxjs';
7 9
import { ConfigService } from '@nestjs/config';
8 9
import { User } from '../users/entities/user.entity';
9
import { GithubUser } from './types/github-user.interface';
10
import { JwtPayload } from './types/jwt-payload.interface';
11
12
@Injectable()
13 9
export class AuthService {
14
  constructor(
15
    @InjectRepository(User)
16 16
    private userRepository: Repository<User>,
17 16
    private jwtService: JwtService,
18 16
    private httpService: HttpService,
19 16
    private configService: ConfigService,
20
  ) {}
21
22
  async exchangeGithubCode(code: string) {
23
    // console.log('Attempting exchange with code:', code);
24
    // console.log('Using client ID:', this.configService.get('OAUTH_CLIENT_ID'));
25
26 3
    const githubToken = await this.getGithubToken(code);
27 3
    const githubUser = await this.getGithubUser(githubToken);
28 3
    const user = await this.findOrCreateUser(githubUser);
29
30
    // Check if the user's account is inactive
31 3
    if (user.roles.includes('inactive')) {
32 1
      throw new ForbiddenException('Your account is inactive.');
33
    }
34
35 2
    const token = this.createToken(user);
36
37 2
    return {
38
      access_token: token,
39
      user: {
40
        githubId: user.githubId,
41
        username: user.username,
42
        email: user.email,
43
        roles: user.roles,
44
        hasAcceptedTerms: user.hasAcceptedTerms,
45
      },
46
    };
47
  }
48
49
  private async getGithubToken(code: string): Promise<string> {
50 4
    const { data } = await firstValueFrom(
51
      this.httpService.post(
52
        'https://github.com/login/oauth/access_token',
53
        {
54
          client_id: this.configService.get('OAUTH_CLIENT_ID'),
55
          client_secret: this.configService.get('OAUTH_CLIENT_SECRET'),
56
          code,
57
        },
58
        {
59
          headers: { Accept: 'application/json' },
60
        },
61
      ),
62
    );
63 4
    return data.access_token;
64
  }
65
66
  private async getGithubUser(token: string): Promise<GithubUser> {
67 4
    const { data } = await firstValueFrom(
68
      this.httpService.get('https://api.github.com/user', {
69
        headers: {
70
          Authorization: `Bearer ${token}`,
71
          Accept: 'application/json',
72
        },
73
      }),
74
    );
75 4
    return data;
76
  }
77
78
  private async findOrCreateUser(githubUser: GithubUser): Promise<User> {
79 5
    let user = await this.userRepository.findOne({
80
      where: { githubId: githubUser.id },
81
    });
82
83 5
    if (!user) {
84 2
      user = await this.userRepository.save(
85
        new User({
86
          githubId: githubUser.id,
87
          username: githubUser.login,
88
          email: githubUser.email,
89
          avatarUrl: githubUser.avatar_url,
90
          roles: ['user'],
91
        }),
92
      );
93
    }
94
95 5
    return user;
96
  }
97
98
  private createToken(user: User): string {
99 2
    const payload: JwtPayload = {
100
      sub: user.githubId,
101
      username: user.username,
102
      email: user.email,
103
      roles: user.roles,
104
    };
105 2
    return this.jwtService.sign(payload);
106
  }
107
108
  async validateUserById(githubId: string): Promise<User | null> {
109 33
    const user = await this.userRepository.findOne({ where: { githubId } });
110
111
    // Check if the user is inactive
112 33
    if (user && user.roles.includes('inactive')) {
113 2
      return null; // Treat inactive users as non-existent
114
    }
115
116 31
    return user;
117
  }
118
119
  async getStatus(user: User) {
120 1
    return {
121
      isAuthenticated: true,
122
      user: {
123
        githubId: user.githubId,
124
        username: user.username,
125
        email: user.email,
126
        roles: user.roles,
127
        hasAcceptedTerms: user.hasAcceptedTerms,
128
      },
129
    };
130
  }
131
}
132